use tauri_sip_client_lib::call_manager::{CallManager, CallDirection, CallStatus};
use tauri_sip_client_lib::audio_manager::AudioManager;
use std::sync::Arc;

#[tokio::test]
async fn test_incoming_call_basic_flow() {
    let call_manager = CallManager::new();
    
    // Simulate incoming call
    let call_id = call_manager.handle_incoming_call(
        "1234567890".to_string(),
        Some("Test Caller".to_string())
    ).await;
    
    // Verify call was created
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    
    let call = call_info.unwrap();
    assert_eq!(call.remote_number, "1234567890");
    assert_eq!(call.remote_name, Some("Test Caller".to_string()));
    assert_eq!(call.direction, CallDirection::Inbound);
    assert_eq!(call.status, CallStatus::Ringing);
    
    // Answer the call
    let result = call_manager.answer_call(call_id.clone()).await;
    assert!(result.is_ok());
    
    // Verify status changed
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Connected);
    
    // Hang up the call
    let result = call_manager.hangup_call(call_id.clone()).await;
    assert!(result.is_ok());
    
    // Verify status changed
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Ended);
}

#[tokio::test]
async fn test_incoming_call_rejection() {
    let call_manager = CallManager::new();
    
    // Simulate incoming call
    let call_id = call_manager.handle_incoming_call(
        "9876543210".to_string(),
        None
    ).await;
    
    // Verify call was created
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Ringing);
    
    // Reject the call
    let result = call_manager.reject_call(call_id.clone()).await;
    assert!(result.is_ok());
    
    // Verify status changed
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Ended);
}

#[tokio::test]
async fn test_incoming_call_timeout() {
    let call_manager = CallManager::new();
    
    // Simulate incoming call
    let call_id = call_manager.handle_incoming_call(
        "5555555555".to_string(),
        Some("Timeout Test".to_string())
    ).await;
    
    // Verify call was created
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Ringing);
    
    // Wait for timeout (30 seconds is too long for test, but we can test the mechanism)
    // In a real test environment, we would mock the timeout duration
    
    // For now, just test that we can cancel the timeout manually
    call_manager.cancel_incoming_call_timeout(&call_id).await;
    
    // The call should still be ringing since we cancelled the timeout
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Ringing);
    
    // Clean up by rejecting the call
    let _ = call_manager.reject_call(call_id).await;
}

#[tokio::test]
async fn test_multiple_incoming_calls() {
    let call_manager = CallManager::new();
    
    // Simulate multiple incoming calls
    let call_id1 = call_manager.handle_incoming_call(
        "1111111111".to_string(),
        Some("Caller 1".to_string())
    ).await;
    
    let call_id2 = call_manager.handle_incoming_call(
        "2222222222".to_string(),
        Some("Caller 2".to_string())
    ).await;
    
    // Verify both calls were created
    let active_calls = call_manager.get_active_calls().await;
    assert_eq!(active_calls.len(), 2);
    
    // Verify call details
    let call1_info = call_manager.get_call_info(&call_id1).await;
    assert!(call1_info.is_some());
    assert_eq!(call1_info.unwrap().remote_number, "1111111111");
    
    let call2_info = call_manager.get_call_info(&call_id2).await;
    assert!(call2_info.is_some());
    assert_eq!(call2_info.unwrap().remote_number, "2222222222");
    
    // Answer first call, reject second
    let result1 = call_manager.answer_call(call_id1.clone()).await;
    assert!(result1.is_ok());
    
    let result2 = call_manager.reject_call(call_id2.clone()).await;
    assert!(result2.is_ok());
    
    // Verify statuses
    let call1_info = call_manager.get_call_info(&call_id1).await;
    assert!(call1_info.is_some());
    assert_eq!(call1_info.unwrap().status, CallStatus::Connected);
    
    let call2_info = call_manager.get_call_info(&call_id2).await;
    assert!(call2_info.is_some());
    assert_eq!(call2_info.unwrap().status, CallStatus::Ended);
    
    // Clean up
    let _ = call_manager.hangup_call(call_id1).await;
}

#[tokio::test]
async fn test_incoming_call_with_audio_integration() {
    let call_manager = CallManager::new();
    let _audio_manager = Arc::new(AudioManager::new().unwrap());
    
    // Simulate incoming call
    let call_id = call_manager.handle_incoming_call(
        "7777777777".to_string(),
        Some("Audio Test".to_string())
    ).await;
    
    // Answer the call (this should start audio stream in real implementation)
    let result = call_manager.answer_call(call_id.clone()).await;
    assert!(result.is_ok());
    
    // In a real implementation, we would verify that audio stream was started
    // For now, just verify the call status
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Connected);
    
    // Test muting during call
    let result = call_manager.mute_call(call_id.clone(), true).await;
    assert!(result.is_ok());
    
    let result = call_manager.mute_call(call_id.clone(), false).await;
    assert!(result.is_ok());
    
    // Hang up the call
    let result = call_manager.hangup_call(call_id.clone()).await;
    assert!(result.is_ok());
    
    // Verify call ended
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    assert_eq!(call_info.unwrap().status, CallStatus::Ended);
}

#[tokio::test]
async fn test_incoming_call_events() {
    // This test would verify that proper events are emitted
    // In a real implementation, we would set up event listeners
    // and verify that IncomingCallEvent, CallStatusEvent, etc. are emitted
    
    let call_manager = CallManager::new();
    
    // Simulate incoming call
    let call_id = call_manager.handle_incoming_call(
        "8888888888".to_string(),
        Some("Event Test".to_string())
    ).await;
    
    // In a real test, we would verify that:
    // 1. IncomingCallEvent was emitted with correct data
    // 2. System notification event was emitted
    // 3. CallStatusEvent is emitted when call status changes
    
    // For now, just verify the call was created
    let call_info = call_manager.get_call_info(&call_id).await;
    assert!(call_info.is_some());
    
    // Clean up
    let _ = call_manager.reject_call(call_id).await;
}

#[tokio::test]
async fn test_incoming_call_notification_data() {
    let call_manager = CallManager::new();
    
    // Test with caller name
    let call_id1 = call_manager.handle_incoming_call(
        "1234567890".to_string(),
        Some("John Doe".to_string())
    ).await;
    
    let call_info = call_manager.get_call_info(&call_id1).await;
    assert!(call_info.is_some());
    let call = call_info.unwrap();
    assert_eq!(call.remote_name, Some("John Doe".to_string()));
    
    // Test without caller name
    let call_id2 = call_manager.handle_incoming_call(
        "0987654321".to_string(),
        None
    ).await;
    
    let call_info = call_manager.get_call_info(&call_id2).await;
    assert!(call_info.is_some());
    let call = call_info.unwrap();
    assert_eq!(call.remote_name, None);
    
    // Clean up
    let _ = call_manager.reject_call(call_id1).await;
    let _ = call_manager.reject_call(call_id2).await;
}